package base.juc;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 不安全的put操作
 *
 * 正确的是，一次put操作 和 remove操作都是线程安全的，所以容量应该是 0
 *
 * 什么时候用 concurrentHashMap 场景
 * 解决HashMap的put操作的时候
 * concurrentHashMap只是保证了 单个方法的原子操作，但是代码间的 线程安全 还是需要 并发处理的
 *
 * 对比结果：以HashMap为例子，仅测试 put操作
 * 1.单线程情况下
 * pool-1-thread-1数字9970插入, 容量0
 * 2.多线程情况下
 * pool-1-thread-1数字9962插入, 容量27
 *
 * 原因是在put方法的时候
 * 这个时候多个线程去修改，该桶中的元素。上个线程还未操作完成，就会导致线程间的操作被覆盖
 *
 * Author: shen qi han
 * Date: 2022/4/7 下午9:35
 */
public class UnSafePutHashMapMain {

    int max = 10000;

    int n = 10;

//    Map<Integer, Integer> map = new HashMap<>();
    ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();

    AtomicInteger atomic = new AtomicInteger();

    CountDownLatch cdl = new CountDownLatch(n);

    class Task implements Runnable{

        @Override
        public void run() {
            while(atomic.get() <= max){
                map.put(atomic.get(), atomic.get());
//                map.remove(atomic.get());
                System.out.println(Thread.currentThread().getName() + "数字" + atomic + "插入, 容量" + map.size());
                atomic.incrementAndGet();
            }
            cdl.countDown();
        }
    }

    public void unsafePut(){
        int qLen = 10;
        BlockingQueue<Runnable> q = new LinkedBlockingQueue<Runnable>(qLen);
        ThreadPoolExecutor pool = new ThreadPoolExecutor(n, n, 0, TimeUnit.MILLISECONDS, q);
        for(int i = 0; i < n; i++){
            Task task = new Task();
            pool.execute(task);
        }
        try {
            cdl.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        pool.shutdown();
        System.out.println("final size: " + map.size());
        System.out.println("finish.");
    }

    public static void main(String[] args) {
        UnSafePutHashMapMain main = new UnSafePutHashMapMain();
        main.unsafePut();
    }

}
